#ifndef _XXXPCSC_CONFIG_H_
#define _XXXPCSC_CONFIG_H_
//配置模块头文件
#include<memory>
#include<string>
#include<sstream>
#include<boost/lexical_cast.hpp> //类型转换
#include"log.h"
#include<yaml-cpp/yaml.h>
#include<list>
#include<vector>
#include<map>
#include<set>
#include<unordered_map>
#include<unordered_set>
#include<functional>
namespace xxXPCSC{
    //基类 通用属性
    class ConfigVarBase{ 
    public:
        typedef std::shared_ptr<ConfigVarBase> ptr;
        ConfigVarBase(const std::string& name,const std::string& description= ""){
            m_name=name;
            m_description=description;
            std::transform(m_name.begin(),m_name.end(),m_name.begin(),::tolower);
        }
        virtual ~ConfigVarBase(){}

        const std::string& getNmae(){ return m_name;}
        const std::string& getDescription(){return m_description;}

        virtual std::string toString()=0;
        virtual bool fromString(const std::string& val)=0;
        virtual std::string getTypeName() const =0;
    protected:
        std::string m_name;
        std::string m_description;
    };
    
    // //从F类型->T的类型 简单类型
    template<class F,class T>
    class LexicalCast{
    public:
        T operator()(const F& v){
            return boost::lexical_cast<T>(v);
        }
    };

    //*****添加常用容器的类型转换 复杂类型 偏特化
    //vector
    // //string -> vector
    template<class T>
    class LexicalCast<std::string,std::vector<T>>{
    public:
        std::vector<T> operator()(const std::string& v){
            YAML::Node node = YAML::Load(v);
            typename std::vector<T> vec;
            std::stringstream ss;
            for(size_t i=0;i<node.size();i++){
                ss.str("");
                ss<<node[i];
                vec.push_back(LexicalCast<std::string,T>()(ss.str()));
            }
            return vec;
        }
    };
    // //vec->string
    template<class T>
    class LexicalCast<std::vector<T>,std::string>{
    public:
        std::string operator()(const std::vector<T>& v){
            YAML::Node node;
            for(auto& i:v){
                node.push_back(YAML::Load(LexicalCast<T,std::string>()(i)));
            }
            std::stringstream ss;
            ss<<node;
            return ss.str();
        }    
    };

    //list
    //string->list
    template<class T>
    class LexicalCast<std::string,std::list<T>>{
    public:
        std::list<T> operator()(const std::string& v){
            YAML::Node node = YAML::Load(v);
            typename std::list<T> vec;
            std::stringstream ss;
            for(size_t i=0;i<node.size();i++){
                ss.str("");
                ss<<node[i];
                vec.push_back(LexicalCast<std::string,T>()(ss.str()));
            }
            return vec;
        }
    };
    // //list->string
    template<class T>
    class LexicalCast<std::list<T>,std::string>{
    public:
        std::string operator()(const std::list<T>& v){
            YAML::Node node;
            for(auto& i:v){
                node.push_back(YAML::Load(LexicalCast<T,std::string>()(i)));
            }
            std::stringstream ss;
            ss<<node;
            return ss.str();
        }    
    };

    //unordered_set 无序set容器  set 容器会自行对存储的数据进行排序，而 unordered_set 容器不会
    //string->unordered_set
    template<class T>
    class LexicalCast<std::string,std::unordered_set<T>>{
    public:
        std::unordered_set<T> operator()(const std::string& v){
            YAML::Node node = YAML::Load(v);
            typename std::unordered_set<T> vec;
            std::stringstream ss;
            for(size_t i=0;i<node.size();i++){
                ss.str("");
                ss<<node[i];
                vec.insert(LexicalCast<std::string,T>()(ss.str()));
            }
            return vec;
        }
    };
    // //unordered_set>string
    template<class T>
    class LexicalCast<std::unordered_set<T>,std::string>{
    public:
        std::string operator()(const std::unordered_set<T>& v){
            YAML::Node node;
            for(auto& i:v){
                node.push_back(YAML::Load(LexicalCast<T,std::string>()(i)));
            }
            std::stringstream ss;
            ss<<node;
            return ss.str();
        }    
    };

    //set
    //string->set
    template<class T>
    class LexicalCast<std::string,std::set<T>>{
    public:
        std::set<T> operator()(const std::string& v){
            YAML::Node node = YAML::Load(v);
            typename std::set<T> vec;
            std::stringstream ss;
            for(size_t i=0;i<node.size();i++){
                ss.str("");
                ss<<node[i];
                vec.insert(LexicalCast<std::string,T>()(ss.str()));
            }
            return vec;
        }
    };
    // //set->string
    template<class T>
    class LexicalCast<std::set<T>,std::string>{
    public:
        std::string operator()(const std::set<T>& v){
            YAML::Node node;
            for(auto& i:v){
                node.push_back(YAML::Load(LexicalCast<T,std::string>()(i)));
            }
            std::stringstream ss;
            ss<<node;
            return ss.str();
        }    
    };

    //map
    //string->map
    template<class T>
    class LexicalCast<std::string, std::map<std::string, T> > {
    public:
    std::map<std::string, T> operator()(const std::string& v) {
        YAML::Node node = YAML::Load(v);
        typename std::map<std::string, T> vec;
        std::stringstream ss;
        for(auto it = node.begin();
                it != node.end(); ++it) {
            ss.str("");
            ss << it->second;
            vec.insert(std::make_pair(it->first.Scalar(),
                        LexicalCast<std::string, T>()(ss.str())));
        }
        return vec;
    }
    };
    // //map->string
    template<class T>
    class LexicalCast<std::map<std::string, T>, std::string> {
    public:
    std::string operator()(const std::map<std::string, T>& v) {
        YAML::Node node(YAML::NodeType::Map);
        for(auto& i : v) {
            node[i.first] = YAML::Load(LexicalCast<T, std::string>()(i.second));
        }
        std::stringstream ss;
        ss << node;
        return ss.str();
    }
    };
    
    //unordered_map
    //string->unordered_map
    template<class T>
    class LexicalCast<std::string, std::unordered_map<std::string, T> > {
    public:
    std::unordered_map<std::string, T> operator()(const std::string& v) {
        YAML::Node node = YAML::Load(v);
        typename std::unordered_map<std::string, T> vec;
        std::stringstream ss;
        for(auto it = node.begin();
                it != node.end(); ++it) {
            ss.str("");
            ss << it->second;
            vec.insert(std::make_pair(it->first.Scalar(),
                        LexicalCast<std::string, T>()(ss.str())));
        }
        return vec;
        }
    };
    // //unordered_map->string
    template<class T>
    class LexicalCast<std::unordered_map<std::string, T>, std::string> {
    public:
    std::string operator()(const std::unordered_map<std::string, T>& v) {
        YAML::Node node(YAML::NodeType::Map);
        for(auto& i : v) {
            node[i.first] = YAML::Load(LexicalCast<T, std::string>()(i.second));
        }
        std::stringstream ss;
        ss << node;
        return ss.str();
        }
    };
    
    //兼容不同类型，使用模板 序列化反序列化
    //,class FromStr=LexicalCast<std::string,T>,class ToStr=LexicalCast<T,std::string>
    template<class T,class FromStr=LexicalCast<std::string,T>,class ToStr=LexicalCast<T,std::string>>
    class ConfigVar:public ConfigVarBase{
    public:
        typedef std::shared_ptr<ConfigVar> ptr;
        //配置项变更时的回调函数
        typedef std::function<void (const T& old_value,const T& new_value)> on_change_cb;
        ConfigVar(const std::string& name,
                  const T& default_value,
                  const std::string& description=""):ConfigVarBase(name,description),m_val(default_value){

        }

        std::string toString() override{
            try{
                //return boost::lexical_cast<std::string>(m_val);
                return ToStr()(m_val);
            }
            catch(std::exception& e){
                XXXPCSC_LOG_ERROR(XXXPCSC_LOG_ROOT())<<"ConfigVar::toString exception"
                                                     <<e.what()<<"convert:"<<typeid(m_val).name()<<"to string";

            }
            return "";
        }
        bool fromString(const std::string& val) override{
            try{
                //m_val=boost::lexical_cast<T>(val);
                setValue(FromStr()(val));
            }catch(std::exception& e){
                XXXPCSC_LOG_ERROR(XXXPCSC_LOG_ROOT())<<"ConfigVar::toString exception "
                                                     <<e.what()<<"convert:"<<typeid(m_val).name();

            }
            return false;
        }
        const T getValue(){return m_val;}
        void setValue(const T& v){
            if(v == m_val)
                return;
            for(auto& i : m_cbs){
                i.second(m_val,v);
            }
            m_val = v;
        }
        std::string getTypeName() const override {return typeid(T).name();}

        void addListener(uint64_t key,on_change_cb cb){m_cbs[key] = cb;}
        void delListener(uint64_t key,on_change_cb cb){m_cbs.erase(key);}
        on_change_cb getListener(uint64_t key){
            auto it = m_cbs.find(key);
            return it==m_cbs.end()?nullptr:it->second;
        }
        void clearListener(){
            m_cbs.clear();
        }
    private:
        T m_val;
        //变更回调函数的map key唯一 一般使用hash
        std::map<uint64_t,on_change_cb> m_cbs;
    };

    class Config{
    public:
        typedef std::map<std::string,ConfigVarBase::ptr> ConfigVarMap;
        template<class T>
        //typename 声明之后的ConfigVar<T>::ptr 是类型名而非变量名
        static typename ConfigVar<T>::ptr Lookup(const std::string& name,const T& default_value,const std::string& description = ""){
            auto it = GetDatas().find(name);
            if(it != GetDatas().end()){
                auto tmp = std::dynamic_pointer_cast<ConfigVar<T>>(it->second);
                if(tmp){
                    XXXPCSC_LOG_INFO(XXXPCSC_LOG_ROOT())<<"Look up name= "<<name<<" exits";
                    return tmp;
                }else{
                    XXXPCSC_LOG_ERROR(XXXPCSC_LOG_ROOT())<<"Look up name= "<<name<<"exits but type not "
                                                        <<typeid(T).name()<<" real type = "<<it->second->getTypeName()
                                                        <<" "<<it->second->toString();
                    return nullptr;
                }
            }
            //此处表明查找异常 限定只能用此处出现的字符只需要小写 若出现之外的则抛出异常 可使用正则表达式
            if(name.find_first_not_of("qazwsxedcrfvtgbyhnujmikolp._-0123456789")!=std::string::npos){//如果查找失败，返回string::npos
                XXXPCSC_LOG_ERROR(XXXPCSC_LOG_ROOT())<<"Look up name invaild"<<name;
                throw std::invalid_argument(name);
            }
            typename ConfigVar<T>::ptr v(new ConfigVar<T>(name,default_value,description));

            GetDatas()[name] = v;//修改键值对中的value 一并初始化
            return v;
        }
        //查找
        template<class T>
        static typename ConfigVar<T>::ptr Lookup(const std::string& name){
            auto it = GetDatas().find(name);
            //找不到
            if(it == GetDatas().end()){
                return nullptr;
            }
            //指针是智能指针时候，向下转换 基类向派生类转换 使用了智能指针只能用dynamic_pointer_cast second表示键值对中数值部分
            return std::dynamic_pointer_cast<ConfigVar<T>>(it->second);
        }
        
        static void LoadFromYaml(const YAML::Node& root); 
        static ConfigVarBase::ptr LookupBase(const std::string& name);
    private:
        static ConfigVarMap& GetDatas(){
            //静态成员初始化问题 采用函数返回静态变量 否静态变量初始化可能落后于其所包含的数据 使用此函数保证一定会被先初始化
            static ConfigVarMap s_datas;
            return s_datas;
        }
       

    };

}

#endif